﻿#ifndef OBJDATA_H
#define OBJDATA_H

#include "ObjLib_global.h"
#include "error.h"
#include "globalfunc.h"
#include <memory>

namespace xvs {


class OBJLIB_EXPORT BaseData : public QObject
{
    Q_OBJECT
public:
    virtual ~BaseData()
    {
    }

    virtual QString DebugString(bool complete = false);

    virtual QString SaveData();//自定义数据保存用，和loadData必须配套使用 Point2D:  { X { 10 } Y { 20 } }    Circle2D: { Origin{X{10} Y{20}} Angle{0} Raidus{100} }
    virtual void LoadData(const QString& dataStr);

    virtual QString TypeName() = 0;

    virtual void Copy(BaseData* rhs) = 0;

private:
    QString PropertyValueString(BaseData *obj, bool complete = false);

};
//return new class_name(*this);

#define DATA_COPY_TYPE(class_name) \
void Copy(BaseData* rhs) override \
{ \
    *this = *qobject_cast<class_name*>(rhs); \
} \
\
virtual QString TypeName() override \
{ \
    return #class_name; \
}\


class OBJLIB_EXPORT PubFunc
{
public:

    static bool IsBaseType(const QString& typeName)
    {
        if (typeName == "Integer" || typeName == "Real" || typeName == "Bool" || typeName == "String" || typeName == "Enum")
            return true;
        return false;
    }

static bool GetStringSignPos(const QString& dataStr,int& leftIdx,int& rightIdx,char leftSign,char rightSign);

// 创建BaseData数据（根据数据类型）
static BaseData* CreateDataObj(const QString& typeName);

};


class OBJLIB_EXPORT Integer : public BaseData
{
    Q_OBJECT
public:
    DATA_COPY_TYPE(Integer)

    Integer();

    Integer(int val);

    Integer(short val);

    Integer(const Integer& rhs);

public:
    Q_INVOKABLE int Value() const;
    Q_INVOKABLE void SetValue(const int value);

    QString DebugString(bool complete = false) override;

    QString SaveData() override;
    void LoadData(const QString& dataStr) override;

public:

    Integer& operator = (const int& rhs);

    Integer& operator = (const Integer& rhs);

    Integer& operator + (const Integer& rhs);

    Integer& operator - (const Integer& rhs);

    Integer& operator * (const Integer& rhs);

    Integer& operator / (const Integer& rhs);

    bool operator == (const Integer& rhs);

    friend QDebug operator << (QDebug debug, const Integer &i)
    {
        debug << i.Value();
        return debug;
    }
private:
    int mValue = 0;
};

class OBJLIB_EXPORT Real : public BaseData
{
    Q_OBJECT
public:
    DATA_COPY_TYPE(Real)

    Real();

    Real(int val);
    Real(float val);

    Real(double val);

    Real(const Real& rhs);

public:
    Q_INVOKABLE float Value() const;
    Q_INVOKABLE void SetValue(const float value);

    QString DebugString(bool complete = false) override;

    QString SaveData() override;
    void LoadData(const QString& dataStr) override;

public:
    Real& operator = (const int& rhs);

    Real& operator = (const float& rhs);

    Real& operator = (const Real& rhs);

    Real& operator + (const Real& rhs);

    Real& operator - (const Real& rhs);

    Real& operator * (const Real& rhs);

    Real& operator / (const Real& rhs);

    bool operator == (const Real& rhs);

    friend QDebug operator << (QDebug debug, const Real &i) {
        debug << i.Value();
        return debug;
    }
private:
    float mValue = 0.0f;
};

class OBJLIB_EXPORT String : public BaseData
{
    Q_OBJECT
public:
    DATA_COPY_TYPE(String)

    String();

    String(QString val);

    String(const String& rhs);
public:
    Q_INVOKABLE QString Value();
    Q_INVOKABLE void SetValue(const QString& value);

    QString DebugString(bool complete = false) override;

    QString SaveData() override;
    void LoadData(const QString& dataStr) override;

public:
    String& operator = (const QString& rhs);

    String& operator = (const String& rhs);

    String& operator + (const String& rhs);

    bool operator ==(const String& rhs);

    friend QDebug operator << (QDebug debug, const String &i) {
        debug << i.mValue;
        return debug;
    }
private:
    QString mValue;
};

class OBJLIB_EXPORT Bool : public BaseData
{
    Q_OBJECT
public:
    DATA_COPY_TYPE(Bool)

    Bool();

    Bool(bool val);

    Bool(int val);

    Bool(const Bool& rhs);

public:
    Q_INVOKABLE bool Value() const;
    Q_INVOKABLE void SetValue(const bool value)
    {
        mValue = value;
    }

    QString DebugString(bool complete = false) override;

    QString SaveData() override;
    void LoadData(const QString& dataStr) override;

public:
    Bool& operator = (const bool& rhs);

    Bool& operator = (const Bool& rhs);

    bool operator ==(const Bool& rhs);

    friend QDebug operator << (QDebug debug, const Bool &i)
    {
        debug << i.Value();
        return debug;
    }
private:
    bool mValue = false;
};

class OBJLIB_EXPORT Enum : public BaseData
{
    Q_OBJECT
public:
    DATA_COPY_TYPE(Enum)

    Enum();

    Enum(const Enum& rhs)
    {
        mValueMap = rhs.mValueMap;
        mValueMap.detach();
        mCurKey = rhs.mCurKey;
    }

    Enum& operator = (const Enum& rhs);
    bool operator == (const Enum& rhs) const;

public:
    QString DebugString(bool complete = false) override
    {
        Q_UNUSED(complete)
        return Value();
    }

    QString SaveData() override;
    void LoadData(const QString& dataStr) override;

public:
    Q_INVOKABLE QString Value();
    Q_INVOKABLE void SetValue(const QString& value);

public:
    void AddEnumItem(int key,QString value);

    void SetKey(int key);

    int Key();

    QStringList ValueList();

protected:
    int mCurKey = 0;
    QMap<int,QString> mValueMap;
};

struct ArrayData : QSharedData
{
    ArrayData()
    {}

    ArrayData(const ArrayData& rhs)
        :QSharedData(rhs)
        ,mItemType(rhs.mItemType)
        ,mArray(rhs.mArray)
    {
    }

    QString mItemType = "";//判断
    QVector<BaseData*> mArray;//隐式共享
};

class OBJLIB_EXPORT Array : public BaseData
{
    Q_OBJECT
public:
    Array();
    Array(const QString itemType);

    Array(const Array& rhs);//深拷贝

    ~Array();

    Array& operator = (const Array &rhs);//深拷贝

public:
    QString TypeName() override
    {
        return d_ptr->mItemType + "Array";
    }

    void Copy(BaseData* rhs) override
    {
        //return new Array(*this);
        *this = *qobject_cast<Array*>(rhs);
    }

public:
    QString ItemType() const;
    void SetItemType(const QString& itemType);

    QString DebugString(bool complete) override;

    void LoadData(const QString& dataStr) override;
    QString SaveData() override;

public:
    template<typename T>
    void Push_Front(const T &value)
    {
        BaseData* obj = qobject_cast<BaseData*>(value);
        if (!obj)
            THROW_ERROR(DomainError,"array data type don't support");

        BaseData* newData = PubFunc::CreateDataObj(obj->TypeName());
        newData->Copy(obj);
        d_ptr->mArray.push_front(newData);
    }

    template<typename T>
    void Push_Back(T& value)
    {
        BaseData* obj = qobject_cast<BaseData*>(&value);
        if (!obj)
            THROW_ERROR(DomainError,"array data type don't support");

        BaseData* newData = PubFunc::CreateDataObj(obj->TypeName());
        newData->Copy(obj);
        d_ptr->mArray.push_back(newData);
    }

    template<typename T>
    T At(int i)
    {
        BaseData* obj = d_ptr->mArray.at(i);
        return *qobject_cast<T*>(obj);
    }

//    BaseData* At(int i) const
//    {
//        return d_ptr->mArray.at(i);
//    }

    template<typename T>
    void SetValue(int i,T value)
    {
        BaseData* obj = qobject_cast<BaseData*>(&value);
        if (!obj)
            THROW_ERROR(DomainError,"array data type don't support");

        if (i < 0 || i >= d_ptr->mArray.size())
            THROW_ERROR(DomainError,"array index out of range");

        BaseData* newData = PubFunc::CreateDataObj(obj->TypeName());
        newData->Copy(obj);

        delete d_ptr->mArray[i];

        d_ptr->mArray[i] = newData;
    }

    int Count() const;

    void _Push_Back(QVariant data);
    BaseData* _AddNewItem();
    QVariant _At(int index);
    void _SetValue(int index,QVariant data);
    int _Size() const;

    void Remove(int i)
    {
        BaseData* bd = d_ptr->mArray.at(i);
        d_ptr->mArray.removeOne(bd);
        delete bd;
    }

    void Clear()
    {
        for (int i = 0; i< d_ptr->mArray.count(); i++)
        {
            BaseData* bd = d_ptr->mArray.at(i);
            delete bd;
        }
        d_ptr->mArray.clear();
    }

private:
    QSharedDataPointer<ArrayData> d_ptr;
};




}



#endif // OBJDATA_H
